home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / dosutils / cluster2.zip / CLUSTER2.BAS < prev    next >
BASIC Source File  |  1996-07-04  |  23KB  |  609 lines

  1. $COMPILE EXE "CLUSTER2.EXE"
  2. '+---------------------------------------------------------------------------+
  3. '| Clusters.bas  --  predicts/reports cluster usages & disk space wasted     |
  4. '|                   based on the cluster sizes used by various operating    |
  5. '|                   systems and how much space is currently in use          |
  6. '|---------------------------------------------------------------------------|
  7. '|Revision History                                                           |
  8. '|---------------------------------------------------------------------------|
  9. '|When        What                                                           |
  10. '| 5 Nov 95   Initial coding and release                                     |
  11. '|19 Nov 95   Fixed problem with counting one too many clusters for          |
  12. '|            each file.  Also fixed the problem with a divide by zero error |
  13. '|            if a drive had only directories (no files) in the root.        |
  14. '|                                                                           |
  15. '|            Added:                                                         |
  16. '|              - the ability to do 512byte clusters (HPFS and NTFS)         |
  17. '|              - Capability to process one drive without zeroing the totals |
  18. '|                                                                           |
  19. '|14 Jun 96   Started Code for version 2.0                                   |
  20. '|              - More detailed reporting                                    |
  21. '|              - just for the fun of it                                     |
  22. '|              - cleaner interface                                          |
  23. '|              - uses modified windowing routines                           |
  24. '|                                                                           |
  25. '+---------------------------------------------------------------------------+
  26. $STACK 32766
  27. $OPTION CNTLBREAK ON
  28. $LIB IPRINT ON
  29. defint a-z
  30.  
  31. %False = 0
  32. %True = NOT(%False)
  33. %FLAGS = 0                    ' constants for CPU registers -- we will be
  34. %AX    = 1                    ' calling some DOS routines later
  35. %BX    = 2
  36. %CX    = 3
  37. %DX    = 4
  38. %SI    = 5
  39. %DI    = 6
  40. %BP    = 7
  41. %DS    = 8
  42. %ES    = 9
  43.  
  44. $INCLUDE "..\lib\PB3BOXES.INC"
  45. %ClustSizes = 6
  46.  
  47. TYPE DTAData                  ' all the information we want about a file
  48.     Reserved AS STRING * 21     ' is in this data structure in DOS memory
  49.   Attr     AS BYTE
  50.   FileTime AS WORD
  51.   FileDate AS WORD
  52.   Size     AS DWORD
  53.   TheName  AS STRING * 13
  54.   TheRest  AS STRING * 21
  55. END TYPE
  56.  
  57. TYPE DirDataType
  58.   DirName    AS STRING * 35
  59.   FileCount  AS LONG
  60.   BytesAlloc AS QUAD
  61.   BytesUsed  AS QUAD
  62. END TYPE
  63.  
  64. SHARED Box1Color%, Box1High%, Box2Color%, Box2High%, Box3Color%, Box3High%
  65. SHARED DirCount%, TempFile$, TempFileNum%, DirNames$(), ReportData&()
  66. SHARED DrvCluster&
  67. DIM DirNames$(0:6000)
  68. DIM DirData AS SHARED DirDataType
  69. DIM ReportData&(1:%ClustSizes,1:5)
  70. '
  71. '  Each primary record in the ReportData& array has 5 elements:
  72. '    ReportData&(x%,1) = Cluster Size
  73. '    ReportData&(x%,2) = Total Clusters Allocated
  74. '    ReportData&(x%,3) = Total Bytes Allocated
  75. '    ReportData&(x%,4) = Total Bytes Used
  76. '    ReportData&(x%,5) = Total Bytes Wasted
  77. '
  78. ReportData&(1,1) = 512        ' initialize the records with default sizes
  79. ReportData&(2,1) = 2048
  80. ReportData&(3,1) = 4096
  81. ReportData&(4,1) = 8192
  82. ReportData&(5,1) = 16384
  83. ReportData&(6,1) = 32768
  84.  
  85. MainBack% = MakeAttr%(%White,%Black)
  86. IF pbvScrnMode = 7 THEN       ' Monochrome Monitor
  87.   MainHigh%  = MakeAttr%(%BrightWhite, %Blue)
  88.   Box1Color% = MakeAttr%(%Black,%White)
  89.   Box1High%  = MakeAttr%(%BrightWhite,%White)
  90.   Box1High2% = MakeAttr%(%BrightWhite,%White)
  91.   Box2Color% = MakeAttr%(%White,%Black)
  92.   Box2High%  = MakeAttr%(%BrightWhite,%Black)
  93.   Box2High2% = MakeAttr%(%BrightWhite,%Black)
  94.   Box3Color% = MakeAttr%(%Black,%White)
  95.   Box3High%  = MakeAttr%(%White,%Black)
  96.   Box3High2% = MakeAttr%(%White,%Black)
  97. ELSE
  98.   MainHigh%  = makeAttr%(%BrightWhite,%Blue)
  99.   Box1Color% = MakeAttr%(%BrightWhite,%Blue)
  100.   Box1High%  = MakeAttr%(%Yellow,%Blue)
  101.   Box1High2% = MakeAttr%(%BrightCyan,%Blue)
  102.   Box2Color% = MakeAttr%(%Black,%Cyan)
  103.   Box2High%  = MakeAttr%(%Blue,%Cyan)
  104.   Box2High2% = MakeAttr%(%Yellow,%Cyan)
  105.   Box3Color% = MakeAttr%(%Black,%Green)
  106.   Box3High%  = MakeAttr%(%BrightWhite,%Green)
  107.   Box3High2% = MakeAttr%(%Yellow,%Green)
  108. END IF
  109.  
  110. '
  111. ' Here, we save the current screen, draw our own, then get started
  112. '
  113. CALL BoxInit(5)
  114. SaveCsrX% = POS(d%)
  115. SaveCsrY% = CSRLIN
  116.  
  117. CALL MakeBox(1,1,25,80,MainBack%,0)
  118. CALL QFILL(2,1,24,80,177,MainBack%)
  119. CALL QFILL(1,1,1,80,32,MainHigh%)
  120. CALL PrtBox(1,1,"Clusters V2.0 (c)1995-96",MainHigh%)
  121. CALL PrtBox(1,46,"Bud Durland - bdurland@northnet.org",MainHigh%)
  122.  
  123. CALL Greeting
  124.  
  125. BeginAgain:
  126. '
  127. ' Get the drive/directory to process
  128. '
  129. VIEW TEXT (1,1)-(80,25)
  130. IF LEN(StartDir$) = 0 THEN StartDir$ = LEFT$(CURDIR$,2)
  131. CALL MakeBox(5,20,8,40,Box2Color%,1)
  132. CALL PrtBox(1,0,"Enter Drive or Directory to process",-1)
  133. CALL LineEdit(8,30,StartDir$,Box2High%,"",CHR$(13,27),ExitKey%,20,50)
  134. CALL RemoveBox
  135. IF ExitKey% = 27 THEN GOTO WrapUp
  136.  
  137. '
  138. '  Fixup the user's input, then load the directory names
  139. '
  140. IF LEN(StartDir$) = 0 THEN StartDir$ = LEFT$(CURDIR$,2)
  141. IF INSTR(StartDir$,":") = 0 THEN StartDir$ = LEFT$(CURDIR$,2)
  142. StartDir$ = UCASE$(RTRIM$(StartDir$, ANY " \/")) + "\"
  143. CALL GetDriveInfo(StartDir$, DrvCluster&, DrvClustCnt&)
  144. CALL LoadDirNames(StartDir$)
  145.  
  146. '
  147. ' Create a screen for displaying the stats
  148. '
  149. CALL MakeBox(3,4,23,74,Box2Color%,1)
  150. a$ = "Scanning Drive " + LEFT$(DirNames$(0),2) + " Curren Cluster Size " + STR$(DrvCluster&)
  151. CALL PrtBox(1,1,a$,-1)
  152. CALL PrtBox(4,1,"Clust         Clust          Kbyte          KByte         KByte  %Slack",Box2High%)
  153. CALL PrtBox(5,1,"Size          Alloc          Alloc           Used        Wasted   space",Box2High%)
  154. CALL PrtBox(6,1,"═══════════════════════════════════════════════════════════════════════",Box2High%)
  155.  
  156. CALL PrtBox(14,0,"HPFS & NTFS (any size)   =    512 byte Clusters",-1)
  157. CALL PrtBox(15,0,"FAT/VFAT    0MB -  128MB =   2048 byte Clusters",-1)
  158. CALL PrtBox(16,0,"FAT/VFAT  129MB -  256MB =   4096 byte Clusters",-1)
  159. CALL PrtBox(17,0,"FAT/VFAT  257MB -  512MB =   8192 byte Clusters",-1)
  160. CALL PrtBox(18,0,"FAT/VFAT  513MB - 1.02GB =  16284 byte Clusters",-1)
  161. CALL PrtBox(19,0,"FAT/VFAT 1.02GB - 2.04GB =  32768 byte Clusters",-1)
  162.  
  163. '
  164. '  Now go through each directory, getting information on each file
  165. '  it contains.  Display the data; and accumulate information about
  166. '  each directory for storage in a temporary file
  167. '
  168. TempFileNum% = AllocTempFile%           ' func returns handle of a temp file
  169. IF TempFileNum% = 0 THEN
  170.   a$ = "Failed to allocate a temporary file" + CHR$(10) + _
  171.        "Clusters cannot continue"
  172.     CALL MsgBox(a$,"",MainHigh%)
  173.   CALL RemoveBox
  174.   END
  175. END IF
  176. FOR DirPtr% = 0 TO DirCount%
  177.   TheDir$ = DirNames$(DirPtr%)
  178.   DirFileCnt& = 0
  179.   CALL PrtBox(2,1,"Dir: ",-1)           ' keep the user entertained
  180.   j$ = TheDir$
  181.   IF LEN(TheDir$) > 65 THEN
  182.       j$ = LEFT$(TheDir$,30) + "...." + RIGHT$(TheDir$,30)
  183.   END IF
  184.   CALL PrtEOL(2,6,TheDir$,Box2High2%)
  185.   TheFile$ = DIR$(TheDir$+"*.*",55)     ' use attr of 55 to get all files
  186.   WHILE LEN(TheFile$) > 0
  187.     INCR FileCnt&,1
  188.     INCR DirFileCnt&,1
  189.     z? = ATTRIB(TheDir$ + TheFile$)
  190.     IF (TheFile$ = ".") OR (TheFile$ = "..") OR _   ' the entries "." and ".."
  191.        (BIT(z?,4)) THEN                             ' are special, and don't
  192.       TheFile$ = DIR$                               ' count here, bit 4 set
  193.       DECR DirFileCnt&                              ' means this file is a
  194.       ITERATE                                       ' dir; don't count it
  195.     END IF
  196.  
  197.     fSize& = GetFileSize&(TheDir$ + TheFile$)
  198.     FOR x% = 1 TO %ClustSizes                       ' Compute file stats
  199.       Cluster& = ReportData&(x%,1)
  200.         TotalFSize&& = TotalFSize&& + k&
  201.  
  202.       ClustAloc& = (fSize& \ Cluster&)              ' get number of whole clust
  203.       f& = fSize& MOD Cluster&                      ' adjust if there is a
  204.       IF f& > 0 THEN INCR ClustAloc&,1              ' partial cluster also
  205.       fWaste& = (ClustAloc& * Cluster&) - fSize&
  206.  
  207.       ReportData&(x%,2) = ReportData&(x%,2) + ClustAloc&
  208.       ReportData&(x%,3) = ReportData&(x%,3) + (ClustAloc& * Cluster&)
  209.       ReportData&(x%,4) = ReportData&(x%,4) + fSize&
  210.       ReportData&(x%,5) = ReportData&(x%,5) + fWaste&
  211.  
  212.       IF Cluster& = DrvCluster& THEN
  213.         INCR DirData.BytesAlloc, (ClustAloc& * Cluster&)
  214.         INCR DirData.BytesUsed, fSize&
  215.       END IF
  216.  
  217.       a$ = SPACE$(72)
  218.       MID$(a$,1,7) = USING$(" ##,###", ReportData&(x%,1))
  219.       MID$(a$,10,10) = USING$(" #,###,###", ReportData&(x%,2))
  220.       MID$(a$,25,10) = USING$(" #,###,###", ReportData&(x%,3) \ 1024)
  221.       MID$(a$,40,10) = USING$(" #,###,###", ReportData&(x%,4) \ 1024)
  222.       MID$(a$,54,10) = USING$(" #,###,###", ReportData&(x%,5) \ 1024)
  223.  
  224.       IF ReportData&(x%,3) > 0 THEN
  225.           a! = 100 - CFIX((ReportData&(x%,4) / ReportData&(x%,3)) * 100)
  226.           MID$(a$,66,10) = USING$("###.##", a!)
  227.       END IF
  228.       IF Cluster& = DrvCluster& THEN
  229.           CALL PrtBox(6+x%,1,a$,Box2high2%)
  230.       ELSE
  231.         CALL PrtBox(6+x%,1,a$,-1)
  232.       END IF
  233.  
  234.     NEXT x%
  235.  
  236.     TheFile$ = DIR$
  237.  
  238.   WEND
  239.   DirData.DirName = TheDir$
  240.   DirData.FileCount = DirFileCnt&
  241.  
  242.   PUT$ #TempFileNum%, DirData
  243.   DirData.DirName = ""
  244.   DirData.FileCount = 0
  245.   DirData.BytesAlloc = 0
  246.   DirData.Bytesused = 0
  247.  
  248. NEXT DirPtr%
  249.  
  250. CALL PrtBox(21,0,"Press 'D' to see current usage by directory; any other to continue",Box2High2%)
  251. WHILE NOT INSTAT:WEND
  252. a$ = INKEY$
  253. IF UCASE$(a$) = "D" THEN CALL ShowDirDetails
  254. CALL PrtEOL(21,1,"",-1)
  255. CALL RemoveBox
  256. a$ = MsgBox$("Would you like to process another drive? Y/N","YN", Box3Color%)
  257. IF a$ = "N" THEN GOTO WrapUp
  258.  
  259. msg$ = "Zero totals before processing?" + CHR$(10) + "Press Y or N"
  260. a$ = MsgBox$(msg$, "YN", Box3Color%)
  261. IF a$ = "Y" THEN
  262.     FOR x% = 1 TO %ClustSizes
  263.     FOR y% = 2 TO 5
  264.         ReportData&(x%,y%) = 0
  265.     NEXT y%
  266.   NEXT x%
  267. END IF
  268.  
  269. CLOSE TempFileNum%
  270. CALL NukeBoxes(1)
  271. GOTO BeginAgain
  272.  
  273. WrapUp:
  274. CLOSE
  275.  
  276. IF LEN(DIR$(TempFile$)) > 0 THEN KILL TempFile$
  277. CALL NukeBoxes(0)
  278. VIEW TEXT (1,1) - (80,25)
  279. LOCATE SaveCsrY%, SaveCsrX%
  280.  
  281. END
  282.  
  283.  
  284. SUB LoadDirNames(StartHere$) LOCAL PUBLIC
  285. '+----------------------------------------------------------------------------+
  286. '|Scans for all the subdirs in a directory tree.                              |
  287. '|    DirPtr% is a pointer to which directory we are currently scanning for     |
  288. '|    more directories.  Each time we find one, we put the name of the new      |
  289. '|    directory on the end of the list, and increase DirCount% by one.  Thus,   |
  290. '|    DirCount% becomes a moving target, and we will just continually move      |
  291. '|    down farther and farther untill all directories have been search to their |
  292. '|  deepest level.                                                            |
  293. '|                                                                            |
  294. '|After we've found all the directories, (DirCount doesn't stay ahead of      |
  295. '|    DirPtr%), we'll sort the list, and exit.                                  |
  296. '|                                                                            |
  297. '|The scan starts at whatever directory is specified in DirNames$(0).  If     |
  298. '| that element is blank, the root directory of the current drive is used     |
  299. '+----------------------------------------------------------------------------+
  300.  
  301. CALL MakeBox(6,10,10,60,Box3Color%,1)
  302. CALL BoxTitle(2,"Loading Directory Names",-1)
  303. CALL SetViewText(0,0)
  304.  
  305. DirPtr% = -1
  306. DirCount% = 0
  307. DirNames$(0) = StartHere$
  308.  
  309. WHILE DirCount% > DirPtr%
  310.     INCR DirPtr%,1
  311.     TheDir$ = DirNames$(DirPtr%)
  312.   IF LEN(TheDir$) < 55 THEN
  313.     PRINT TheDir$;" ";
  314.   ELSE
  315.     PRINT LEFT$(TheDir$,25);"....";RIGHT$(TheDir$,25);" ";
  316.   END IF
  317.   ix% = POS(g%)
  318.   iy% = CSRLIN
  319. '+----------------------------------------------------------------------------+
  320. '| Use an attribute value of 23.  This will make DIR$ return directory names  |
  321. '| and "normal" files, as well has hidden and system directories              |
  322. '+----------------------------------------------------------------------------+
  323.   Spin$ = "|/-\"
  324.   SpinPtr% = 1
  325.     x$ = DIR$(TheDir$+"*.*",23)
  326.     WHILE x$ <> ""
  327.         TheFile$ = TheDir$ + x$
  328.     LOCATE iy%,ix%
  329.     PRINT MID$(Spin$,SpinPtr%,1);
  330.     INCR SpinPtr%,1
  331.     IF SpinPtr% > LEN(Spin$) THEN SpinPtr% = 1
  332. '+----------------------------------------------------------------------------+
  333. '| Check the attribute of the returned file name.  If bit 4 is set, then the  |
  334. '| file is a directory.  If it's a directory, then increase the DirCount% and |
  335. '| store this directory name.                                                 |
  336. '+----------------------------------------------------------------------------+
  337.     z? = ATTRIB(TheFile$)
  338.         IF BIT(z?,4) THEN
  339.             INCR DirCount%,1
  340.             TheFile$ = RTRIM$(TheFile$, ANY CHR$(0,32,92,47)) + "\"  'remove /\ too
  341.             DirNames$(DirCount%) = TheFile$
  342.         END IF
  343.         x$ = DIR$
  344.     WEND
  345.   LOCATE iy%,ix%
  346.   PRINT " "
  347.   IF DirCount% => UBOUND(DirNames$) THEN EXIT LOOP
  348. WEND
  349.  
  350. PRINT "Sorting..."
  351. ARRAY SORT DirNames$() FOR DirCount%+1    ' sort directory names
  352. CALL RemoveBox
  353.  
  354. END SUB
  355.  
  356. SUB ShowDirDetails
  357. '╒═══════════════════════════════════════════════════════════════════════╕
  358. '│ This sub will show the current usage details for each directory       │
  359. '│ that was just scanned                                                 │
  360. '╘═══════════════════════════════════════════════════════════════════════╛
  361. ByTotal&& = 0
  362. AlcTotal&& = 0
  363. UseTotal&& = 0
  364. DirTotal&& = 0
  365.  
  366. PUT$ #TempFileNum%, ""
  367. SEEK #TempFileNum%,0
  368.  
  369. CALL ClearBox(-1,-1)
  370. CALL PrtBox(3,0,"Please wait while report is formatted",-1)
  371. DIM HUGE Report$(DirCount%)
  372. FOR xx& = 1 TO DirCount%
  373.   IF EOF(TempFileNum%) THEN EXIT FOR
  374.   GET #TempFileNum%,,DirData
  375.   a$ = SPACE$(72)
  376.   b$ = RTRIM$(DirData.DirName, ANY CHR$(32,0))
  377.   IF LEN(b$) = 0 THEN EXIT FOR
  378.   IF LEN(b$) > 30 THEN
  379.     c$ = RIGHT$(b$,1)
  380.     FOR k% = (LEN(b$)-1) TO 1 STEP -1
  381.       c$ = MID$(b$,k%,1) + c$
  382.       IF MID$(b$,k%,1) = "\" THEN EXIT FOR
  383.     NEXT k%
  384.     k% = INSTR(4,b$,"\")
  385.     b$ = LEFT$(b$,k%) + "...." + c$
  386.   END IF
  387.   MID$(a$,1,30) = b$
  388.   MID$(a$,32,7) = USING$(" ##,###", DirData.FileCount)
  389.   MID$(a$,40,10) = USING$(" #,###,###", (DirData.BytesAlloc \ 1024))
  390.   MID$(a$,53,10) = USING$(" #,###,###", (DirData.BytesUsed \ 1024))
  391.  
  392.   IF DirData.BytesAlloc > 0 THEN
  393.     a! = 100 - CFIX((DirData.BytesUsed / DirData.BytesAlloc) * 100)
  394.     MID$(a$,65,6) = USING$("###.##", a!)
  395.   END IF
  396.  
  397.   Report$(xx&) = a$
  398.  
  399. NEXT xx&
  400.  
  401.  
  402.   CALL ClearBox(-1,-1)
  403.   CALL PrtBox(1,1,"Directory",Box2High%)
  404.   CALL PrtBox(1,33,"  File     Kbytes       KBytes  %Slack",Box2High%)
  405.   CALL PrtBox(2,33," Count      Alloc         Used   Space",Box2High%)
  406.   CALL PrtBox(3,1,STRING$(72,205),Box2high%)
  407.   CALL MakeBox(6,4,20,74,Box2Color%,1)
  408.   CALL ScrollList((DirCount%), Report$(), %False)
  409.   CALL RemoveBox
  410.  
  411. END SUB
  412.  
  413. FUNCTION GetFileSize&(BYVAL TheFile$) LOCAL PUBLIC
  414. '+---------------------------------------------------------------------------+
  415. '| Returns the size (in bytes) of the specified file.  Will preserve the     |
  416. '| current DOS DTA. (see below)                                              |
  417. '+---------------------------------------------------------------------------+
  418.  
  419.   DIM MyDTA as DtaData
  420.   CALL FindOldDta(OldSeg??, OldOff??)              ' so we can go back
  421.   a$ = SPACE$(LEN(MyDTA))
  422.   NewSeg?? = BITS??(STRSEG(a$))
  423.   NewOff?? = BITS??(STRPTR(a$))
  424.   CALL SetNewDta(NewSeg??, NewOff??)
  425.  
  426.   REG %AX, &H4E00
  427.   Victim$ = TheFile$ + CHR$(0)
  428.   REG %CX, &H16        ' find all files and sub dirs
  429.   REG %DS, STRSEG(Victim$)
  430.   REG %DX, STRPTR(Victim$)
  431.   CALL INTERRUPT &H21
  432.  
  433.   RetCode?? = REG(%Flags)
  434.   IF BIT(RetCode??,0) THEN                      ' error flag set
  435.     GetFileSize& = -1
  436.   ELSE
  437.     LSET MyDta = a$
  438.     GetFileSize& = MyDta.Size
  439.   END IF
  440.  
  441. ' Reset the old DTA
  442.   CALL SetNewDTA(OldSeg??, OldOff??)
  443. END FUNCTION
  444.  
  445.  
  446. '+--------------------------------------------------------------------------+
  447. '| The DTA (disk transfer address) is a data structure in DOS memory that   |
  448. '| holds information about the last file DOS was asked to look for.  DOS    |
  449. '| allows a program to determine where the DTA is, and to set it's own area |
  450. '| for the DTA.                                                             |
  451. '|                                                                          |
  452. '| PowerBASIC uses the DTA when you use the DIR$ function.   The first      |
  453. '| time you use it, you specify a file name: a$ = DIR$("*.*").  After that, |
  454. '| you DOS uses information leftover in the DTA to find the next file when  |
  455. '| you use b$ = DIR$.  Everytime you specify a file, even with wildcards,   |
  456. '| the search starts over.                                                  |
  457. '|                                                                          |
  458. '| In this program, that could be a pain -- our main loop is searching      |
  459. '| through all the file in a directory {x$ = DIR$(TheDir$+"*.*",23)} to     |
  460. '| get the names, then CALLing a sub to get the file size.  It's important  |
  461. '| that the SUB not distrub the DTA, or the program would never get past    |
  462. '| the first file in a directory!                                           |
  463. '|                                                                          |
  464. '| So, these two routines allow us to find & preserve the old DTA data,     |
  465. '| while temporarily substituting a different one for doing the size check  |
  466. '+--------------------------------------------------------------------------+
  467.  
  468.  
  469. SUB FindOldDTA(TheSeg??, TheOffSet??) LOCAL PUBLIC
  470. '+------------------------------------------------------------------------+
  471. '|Determines where the current DTA is, and returns it's segment/offset    |
  472. '+------------------------------------------------------------------------+
  473.  REG %AX, &H2F00          'Use DOS service INT 21/function 2F, to
  474.  CALL INTERRUPT &H21      'Find where the current DTA is
  475.  TheSeg?? = REG(%ES)       'Segment of location of default DTA
  476.  TheOffset??  = REG(%BX)   'Offset into the segment for default DTA
  477. END SUB
  478.  
  479.  
  480. SUB SetNewDTA(BYVAL TheSeg??, BYVAL TheOffSet??) LOCAL PUBLIC
  481. '+------------------------------------------------------------------------+
  482. '|Installs a new DTA address for DOS to use                               |
  483. '+------------------------------------------------------------------------+
  484.  REG %AX, &H1A00              'Use another Dos Service (21/1A) to set the DTA
  485.  REG %DS, TheSeg??             'Load the segment of it's location
  486.  REG %DX, TheOffSet??          '  and the offset
  487.  CALL INTERRUPT &H21          'Call the DOS service
  488. END SUB
  489.  
  490. SUB GetDriveInfo(BYVAL TheDrive$, DrvCluster&, ClusterCnt&) LOCAL PUBLIC
  491. '+--------------------------------------------------------------------------+
  492. '| This sub will determine some of the geometry of the drive -- the sector  |
  493. '| size, and the number of sectors per cluster.  From that, we can compute  |
  494. '| the cluster size for this drive                                          |
  495. '+--------------------------------------------------------------------------+
  496.  
  497.   dd$ = UCASE$(TheDrive$)
  498.   drv% = ASC(dd$) - 64                  ' unlike BIOS functions, A is drive 1
  499.   IF (drv% < 1) OR (drv% > 26) THEN     ' exit if bad disk name
  500.     DrvCluster& = -1
  501.     EXIT SUB
  502.   END IF
  503.  
  504.   REG %AX, &H3600             ' DOS Function call - INT 21H/36
  505.   REG %DX, drv%               ' Drive to check
  506.   CALL INTERRUPT &H21         ' Call DOS Int
  507.  
  508.  
  509.   Sectors&     = REG(%AX)        ' Sectors per cluster
  510.   SectorSize&  = REG(%CX)        ' Sector size in bytes
  511.   TClusters&   = REG(%DX)          ' Total Clusters on disk
  512.   DrvCluster&  = Sectors& * SectorSize&
  513.  
  514.   IF TClusters& > 0 THEN
  515.       ClusterCnt& = TClusters&
  516.   ELSE
  517.       ClusterCnt&  = 65536 - TClusters&
  518.   END IF
  519.  
  520. END SUB
  521.  
  522. FUNCTION AllocTempFile% LOCAL PUBLIC
  523. '+--------------------------------------------------------------------------+
  524. '| Allocates a temporary file;  if successful, returns handle of opened     |
  525. '| file.  If not, returns 0                                                 |
  526. '+--------------------------------------------------------------------------+
  527. ON LOCAL ERROR GOTO ATFErr
  528.  
  529. ' use temp dir defined in Autoexec, if any.  otherwise, use current DIR
  530.   a$ = ENVIRON$("TEMP")
  531.   IF LEN(a$) = 0 THEN a$ = CURDIR$
  532.  
  533. ' Assign file name and delete it if it exists
  534.   TempFile$ = RTRIM$(a$, ANY " /\") + "\$$CLUS$$.TMP"
  535.   IF LEN(DIR$(TempFile$)) > 0 THEN KILL TempFile$
  536.  
  537. ' Open the file, and return the handle
  538.   x% = FREEFILE
  539.   OPEN TempFile$ FOR BINARY AS x%
  540.  
  541. ATFDone:
  542.  
  543.   AllocTempFile% = x%
  544.   EXIT FUNCTION
  545.  
  546. ATFErr:
  547.  
  548.   x% = 0
  549.   RESUME ATFDone
  550.  
  551. END FUNCTION
  552.  
  553. SUB Greeting LOCAL PUBLIC
  554.  
  555.   RESTORE GreetData
  556.   DIM Text$(1:100)
  557.   FOR x% = 1 TO 100
  558.     READ a$
  559.     IF a$ = "/END/" THEN
  560.       DECR x%,1
  561.       EXIT FOR
  562.     END IF
  563.     Text$(x%) = a$
  564.   NEXT x%
  565.  
  566.   CALL MakeBox(3,5,21,70,Box1Color%,1)
  567.   CALL ScrollList(x%, Text$(), %True)
  568.   CALL RemoveBox
  569.  
  570. END SUB
  571.  
  572. GreetData:
  573.  
  574. DATA  "Thanks for using CLUSTERS"
  575. DATA  " "
  576. DATA  "This program will examine the sizes of the files stored on"
  577. DATA  "the drive you specify.  It will then calculate how much of"
  578. DATA  "the disk space allocated to it is 'slack'.  The README.TXT"
  579. DATA  "file that accompanies this program explains slack space,"
  580. DATA  "what causes it and how to reduce it.  CLUSTERS will calculate"
  581. DATA  "the disk allocation and slack space for all the possible"
  582. DATA  "cluster sizes, and will highlight whichever one the specified"
  583. DATA  "disk drive is currently using."
  584. DATA  " "
  585. DATA  "After examining all of the files, CLUSTERS will ask if you would"
  586. DATA  "like to see a detailed listing, arranged by directory.  This"
  587. DATA  "lets you pinpoint directories that are very wasteful of space"
  588. DATA  "(such as icon directories), and take appropriate action.  In"
  589. DATA  "the list, as in all CLUSTERS displays, 1Kbyte = 1024 bytes"
  590. DATA  " "
  591. DATA  "Please note that CLUSTERS will report a different number for"
  592. DATA  "the amount disk space used than some other DOS utilities.  This"
  593. DATA  "is because it only examine files; CLUSTERS does not account for"
  594. DATA  "the amount of disk space taken up by the actual directory"
  595. DATA  "listings themselves."
  596. DATA  " "
  597. DATA  "Also, if you are using an HPFS or NTFS partitions, CLUSTERS"
  598. DATA  "will erroneously report the cluster size as whatever is"
  599. DATA  "appropriate for the partition size;  This is because the"
  600. DATA  "operating system 'lies' to DOS programs when they ask about"
  601. DATA  "the geometry of the disk.  HPFS and NTFS partitions always"
  602. DATA  "use 512byte partitions and are *very* efficient"
  603. DATA  " "
  604. DATA  "Press ESC to continue"
  605. DATA  "/END/"
  606.  
  607.  
  608. $LINK "..\LIB\PB3BOXES.PBL"
  609.